package cn.yr.common.core.utils.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.UUID;


/**
 * @Title: JwtUtil
 * @Description: JWT工具类
 *  https://github.com/auth0/java-jwt
 * @author Lang
 * @date 2020/6/8 21:19
 */
public class JwtUtil {

    private static JwtProperties jwtProperties;

    private  static final String TOKEN_NAME = "token";

    public static void setJwtProperties(JwtProperties jwtProperties) {
        JwtUtil.jwtProperties = jwtProperties;
    }

    public static String generateToken(String uid){
        return generateToken(uid,null,null);
    }

    static {
        setJwtProperties(new JwtProperties());
    }

    /**
     * 生成JWT Token
     * @param uid       存储对象
     * @param secretKey           秘钥
     * @param expireSecond 过期时间和单位
     * @return token
     */
    public static String generateToken(String uid, String secretKey, Long expireSecond) {
        try {
            if (uid==null||uid=="") {
                return null;
            }
            // 如果盐值为空，则使用默认值：666666
            if (secretKey==null||secretKey=="") {
                secretKey = jwtProperties.getSecretKey();
            }
            // 过期时间，单位：秒
            // 默认过期时间为1小时
            if (expireSecond == null) {
                expireSecond = jwtProperties.getExpireSecond();
            }
            Date expireDate = new Date(System.currentTimeMillis()+expireSecond*1000);
            // 生成token
            Algorithm algorithm = Algorithm.HMAC256(secretKey);
            return  JWT.create()
                    .withClaim(TOKEN_NAME, uid)
                    // jwt唯一id
                    .withJWTId(UUID.randomUUID().toString())
                    // 签发人
                    .withIssuer(jwtProperties.getIssuer())
                    // 主题
                    .withSubject(jwtProperties.getSubject())
                    // 签发的目标
                    .withAudience(jwtProperties.getAudience())
                    // 签名时间
                    .withIssuedAt(new Date())
                    // token过期时间
                    .withExpiresAt(expireDate)
                    // 签名
                    .sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Description 验证token
     * @author Lang
     * @Date 2020/6/23 23:04
     */
    public static boolean verifyToken(String token){
        return verifyToken(token,null);
    }

    /**
     * @Description 校验token 忽略过期时间
     * @author Lang
     * @Date 2020/6/23 23:04
     */
    public static boolean verifyTokenIgnoreExpire(String token){
        return verifyTokenIgnoreExpire(token,null);
    }

    public static boolean verifyToken(String token, String secretKey) {
        try {
            return verifyTokenBase(token,secretKey);
        }catch (Exception e){
            return false;
        }
    }

    private static boolean verifyTokenBase(String token, String secretKey) {
        if(secretKey==null||secretKey==""){
            secretKey = jwtProperties.getSecretKey();
        }
        Algorithm algorithm = Algorithm.HMAC256(secretKey);
        JWTVerifier verifier = JWT.require(algorithm)
                // 签发人
                .withIssuer(jwtProperties.getIssuer())
                // 主题
                .withSubject(jwtProperties.getSubject())
                // 签发的目标
                .withAudience(jwtProperties.getAudience())
                .build();
        DecodedJWT jwt = verifier.verify(token);
        if (jwt != null) {
            return true;
        }
        return false;
    }

    public static boolean verifyTokenIgnoreExpire(String token, String secretKey){
        try {
            return verifyTokenBase(token,secretKey);
        }catch (TokenExpiredException e){
            return true;
        } catch (Exception e){
            return false;
        }
    }


    /**
     * 解析token，获取token数据
     * @param token
     * @return
     */
    public static DecodedJWT getJwtInfo(String token) {
        return JWT.decode(token);
    }

    /**
     * 获取用户名
     * @param token
     * @return
     */
    public static String getUid(String token) {
        if (token==null||token==""){
            return null;
        }
        DecodedJWT decodedJwt = getJwtInfo(token);
        return  decodedJwt.getClaim(TOKEN_NAME).asString();
    }

    /**
     * 获取创建时间
     * @param token
     * @return
     */
    public static Date getIssuedAt(String token) {
        DecodedJWT decodedJwt = getJwtInfo(token);
        return decodedJwt.getIssuedAt();
    }

    /**
     * 获取过期时间
     * @param token
     * @return
     */
    public static Date getExpireDate(String token) {
        DecodedJWT decodedJwt = getJwtInfo(token);
        return decodedJwt.getExpiresAt();
    }

    /**
     * 判断token是否已过期
     * @param token
     * @return
     */
    public static boolean isExpired(String token) {
        Date expireDate = getExpireDate(token);
        if (expireDate == null) {
            return true;
        }
        return expireDate.before(new Date());
    }

}
